package com.canbot.u05.utils

import android.graphics.ImageFormat
import android.graphics.Rect
import android.graphics.YuvImage
import android.media.Image

import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
import java.io.FileOutputStream
import java.io.IOException
import java.nio.ByteBuffer

/**
 * Created by zmp on 2017/3/31.
 */
class ImageUtil {


        //NV21: YYYY VUVU

        internal fun NV21_mirror(nv21_data: ByteArray, width: Int, height: Int): ByteArray {
                var i: Int
                var left: Int
                var right: Int
                var temp: Byte
                var startPos = 0

                // mirror Y
                i = 0
                while (i < height) {
                        left = startPos
                        right = startPos + width - 1
                        while (left < right) {
                                temp = nv21_data[left]
                                nv21_data[left] = nv21_data[right]
                                nv21_data[right] = temp
                                left++
                                right--
                        }
                        startPos += width
                        i++
                }


                // mirror U and V
                val offset = width * height
                startPos = 0
                i = 0
                while (i < height / 2) {
                        left = offset + startPos
                        right = offset + startPos + width - 2
                        while (left < right) {
                                temp = nv21_data[left]
                                nv21_data[left] = nv21_data[right]
                                nv21_data[right] = temp
                                left++
                                right--

                                temp = nv21_data[left]
                                nv21_data[left] = nv21_data[right]
                                nv21_data[right] = temp
                                left++
                                right--
                        }
                        startPos += width
                        i++
                }
                return nv21_data
        }

        companion object {

                val OR_0 = 0

                val OR_90 = 1

                val OR_180 = 2

                val OR_270 = 3

                val OR_DEFAULT = 3

                fun imageToByteArray(image: Image?): ByteArray? {
                        var data: ByteArray? = null
                        if (image == null) {
                                return null
                        }
                        if (image.format == ImageFormat.JPEG) {
                                val planes = image.planes
                                val buffer = planes[0].buffer
                                data = ByteArray(buffer.capacity())
                                buffer.get(data)
                                return data
                        } else if (image.format == ImageFormat.YUV_420_888) {
                                data = NV21toJPEG(
                                        YUV_420_888toNV21(image),
                                        image.width, image.height, OR_DEFAULT)
                        }
                        return data
                }

                fun YUV_420_888toNV21(image: Image): ByteArray {
                        val nv21: ByteArray
                        val yBuffer = image.planes[0].buffer
                        val uBuffer = image.planes[1].buffer
                        val vBuffer = image.planes[2].buffer

                        val ySize = yBuffer.remaining()
                        val uSize = uBuffer.remaining()
                        val vSize = vBuffer.remaining()
                        val u = ByteArray(uSize)
                        val v = ByteArray(vSize)
                        uBuffer.get(u)
                        vBuffer.get(v)
                        nv21 = ByteArray(ySize + uSize + vSize)
                        //U and V are swapped
                        yBuffer.get(nv21, 0, ySize)
                        for (i in 0 until vSize) {
                                nv21[ySize + (i shl 1)] = v[i]
                                nv21[ySize + (i shl 1) + 1] = u[i]
                        }
                        return nv21
                }

                fun NV21toJPEG(nv21: ByteArray, width: Int, height: Int, o: Int): ByteArray {
                        var bytes = nv21
                        var w = width
                        var h = height
                        when (o) {
                                0 -> {
                                }
                                1 -> {
                                        w = height
                                        h = width
                                        bytes = nv21Rotate90(nv21, width, height)
                                }
                                2 -> bytes = nv21Rotate180(nv21, width, height)
                                3 -> {
                                        w = height
                                        h = width
                                        bytes = nv21Rotate270(nv21, width, height)
                                }
                                else -> {
                                }
                        }

                        val out = ByteArrayOutputStream()
                        val yuv = YuvImage(bytes, ImageFormat.NV21, w, h, null)
                        yuv.compressToJpeg(Rect(0, 0, w, h), 100, out)
                        return out.toByteArray()
                }

                fun writeFrame(fileName: String, data: ByteArray) {
                        try {
                                val bos = BufferedOutputStream(FileOutputStream(fileName))
                                bos.write(data)
                                bos.flush()
                                bos.close()
                        } catch (e: IOException) {
                                e.printStackTrace()
                        }

                }

                fun nv21Rotate270(src: ByteArray, srcWidth: Int, height: Int): ByteArray {
                        val dst = ByteArray(src.size)
                        val wh = srcWidth * height
                        val uvHeight = height shr 1//uvHeight = height / 2

                        //旋转Y
                        var k = 0
                        for (i in 0 until srcWidth) {
                                var nPos = srcWidth - 1
                                for (j in 0 until height) {
                                        dst[k] = src[nPos - i]
                                        k++
                                        nPos += srcWidth
                                }
                        }

                        var i = 0
                        while (i < srcWidth) {
                                var nPos = wh + srcWidth - 1
                                for (j in 0 until uvHeight) {
                                        dst[k] = src[nPos - i - 1]
                                        dst[k + 1] = src[nPos - i]
                                        k += 2
                                        nPos += srcWidth
                                }
                                i += 2
                        }

                        return dst
                }

                private fun nv21Rotate90(src: ByteArray, width: Int, height: Int): ByteArray {
                        val des = ByteArray(src.size)

                        val wh = width * height
                        val uvHeight = height shr 1
                        //旋转Y
                        var k = 0
                        for (i in 0 until width) {
                                var nPos = width * (height - 1)
                                for (j in 0 until height) {
                                        des[k] = src[nPos + i]
                                        k++
                                        nPos -= width
                                }
                        }

                        k = wh * 3 / 2 - 1
                        var x = width - 1
                        while (x > 0) {
                                var nPos = 0
                                for (j in 0 until uvHeight) {
                                        des[k] = src[wh + nPos + x]
                                        k--
                                        des[k] = src[wh + nPos + (x - 1)]
                                        k--
                                        nPos += width
                                }
                                x = x - 2
                        }

                        return des
                }


                private fun nv21Rotate180(data: ByteArray, width: Int, height: Int): ByteArray {
                        val des = ByteArray(data.size)
                        var i: Int
                        var k = 0
                        val wh = width * height
                        val uvHeight = height shr 1
                        i = wh - 1
                        while (i >= 0) {
                                des[k] = data[i]
                                k++
                                i--
                        }

                        i = wh * 3 / 2 - 1
                        while (i >= wh) {
                                des[k++] = data[i - 1]
                                des[k++] = data[i]
                                i -= 2
                        }
                        return des
                }
        }

}